// CHECKSTYLE_OFF: Copyrighted to the Android Open Source Project.
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
// CHECKSTYLE_ON

package java.io;

import static javaemul.internal.InternalPreconditions.checkNotNull;

/**
 * A writable sink for bytes.
 *
 * <p>Most clients will use output streams that write data to the file system ({@link
 * FileOutputStream}), the network ({@link java.net.Socket#getOutputStream()}/{@link
 * java.net.HttpURLConnection#getOutputStream()}), or to an in-memory byte array ({@link
 * ByteArrayOutputStream}).
 *
 * <p>Use {@link OutputStreamWriter} to adapt a byte stream like this one into a character stream.
 *
 * <p>Most clients should wrap their output stream with {@link BufferedOutputStream}. Callers that
 * do only bulk writes may omit buffering.
 *
 * <h3>Subclassing OutputStream</h3>
 *
 * Subclasses that decorate another output stream should consider subclassing {@link
 * FilterOutputStream}, which delegates all calls to the target output stream.
 *
 * <p>All output stream subclasses should override <strong>both</strong> {@link #write(int)} and
 * {@link #write(byte[],int,int) write(byte[],int,int)}. The three argument overload is necessary
 * for bulk access to the data. This is much more efficient than byte-by-byte access.
 *
 * @see InputStream
 *     <p>The implementation provided by this class behaves as described in the Java API
 *     documentation except for {@link write(int)} which throws an exception of type {@link
 *     java.lang.UnsupportedOperationException} instead of being abstract.
 */
public abstract class OutputStream implements Closeable, Flushable {

  /** Default constructor. */
  public OutputStream() {}

  /**
   * Closes this stream. Implementations of this method should free any resources used by the
   * stream. This implementation does nothing.
   *
   * @throws IOException if an error occurs while closing this stream.
   */
  @Override
  public void close() throws IOException {
    /* empty */
  }

  /**
   * Flushes this stream. Implementations of this method should ensure that any buffered data is
   * written out. This implementation does nothing.
   *
   * @throws IOException if an error occurs while flushing this stream.
   */
  @Override
  public void flush() throws IOException {
    /* empty */
  }

  /** Equivalent to {@code write(buffer, 0, buffer.length)}. */
  public void write(byte[] buffer) throws IOException {
    // Note that GWT will throw a JavascriptException rather than a NullPointerException if we
    // skip this check and the buffer array is null. This way we ensure that this implementation
    // behaves in the same way as the classes that are emulated.
    checkNotNull(buffer);
    write(buffer, 0, buffer.length);
  }

  /**
   * Writes {@code count} bytes from the byte array {@code buffer} starting at position {@code
   * offset} to this stream.
   *
   * @param buffer the buffer to be written.
   * @param offset the start position in {@code buffer} from where to get bytes.
   * @param count the number of bytes from {@code buffer} to write to this stream.
   * @throws IOException if an error occurs while writing to this stream.
   * @throws IndexOutOfBoundsException if {@code offset < 0} or {@code count < 0}, or if {@code
   *     offset + count} is bigger than the length of {@code buffer}.
   */
  public void write(byte[] buffer, int offset, int count) throws IOException {
    IOUtils.checkOffsetAndCount(buffer, offset, count);
    for (int i = offset; i < offset + count; i++) {
      write(buffer[i]);
    }
  }

  /**
   * Writes a single byte to this stream. Only the least significant byte of the integer {@code
   * oneByte} is written to the stream.
   *
   * @param oneByte the byte to be written.
   * @throws IOException if an error occurs while writing to this stream.
   */
  public abstract void write(int oneByte) throws IOException;
}
